using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Arroguella.Utilities;


namespace Arroguella.Panels.Popups
{
    /// <summary>
    /// A simple popup menu, navigable with the keyboard and mouse.
    /// </summary>
    public class PopupMenu : ScreenPanel
    {
        #region Constructor

        public PopupMenu(Game game, Rectangle sizeAndShape, string title, string subtitle, List<object> choices, Color color, Color backgroundColor)
            : base(game)
        {
            SizeAndShape = sizeAndShape;
            Title = title;
            Subtitle = subtitle;
            Choices = choices;
            Color = color;
            BackgroundColor = backgroundColor;

            Initialize();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // Set up bounding rectangles
            SetSizeAndShape(SizeAndShape.X, SizeAndShape.Y, SizeAndShape.Width, SizeAndShape.Height);
            HeaderRect = new Rectangle(SizeAndShape.X, SizeAndShape.Y, SizeAndShape.Width, 50);
            TitleRect = new Rectangle(SizeAndShape.X + 5, SizeAndShape.Y + 2, SizeAndShape.Width - 10, 25);
            SubtitleRect = new Rectangle(TitleRect.X, TitleRect.Y + TitleRect.Height + 2, TitleRect.Width, 20);
            CreateBodyRectangle(SizeAndShape, HeaderRect);

            // TODO - Boundary checking: Don't draw beyond the bottom of the menu
            int optionHeight = 20;
            bool selected = true;
            Rectangle optionRect = new Rectangle(BodyRect.X + 5, BodyRect.Y + 10, BodyRect.Width - 10, optionHeight);
            foreach (object choice in Choices)
            {
                PopupMenuOption option = CreateOption(choice, optionRect);

                // Auto-select the first option
                if (selected)
                {
                    option.IsSelected = true;
                    SelectedOption = 0;
                    selected = false;
                }

                Options.Add(option);
                optionRect = new Rectangle(optionRect.X, optionRect.Y + optionHeight + 10, optionRect.Width, optionHeight);
            }

            base.Initialize();
        }

        /// <summary>
        /// Creates the actual option control within the menu
        /// </summary>
        protected virtual PopupMenuOption CreateOption(object choice, Rectangle rect)
        {
            return new PopupMenuOption(choice.ToString(), rect, Color, Arroguella);
        }

        /// <summary>
        /// Creates and defines the rectangle for the body of the menu, the section where the options are.
        /// </summary>
        protected virtual void CreateBodyRectangle(Rectangle sizeAndShape, Rectangle header)
        {
            BodyRect = new Rectangle(sizeAndShape.X + 5, header.Y + header.Height, header.Width - 10, sizeAndShape.Height - header.Height);
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {        
            base.Update(gameTime);
        }

        public override void Draw(SpriteBatch spriteBatch)
        {
            DrawBaseMenu(spriteBatch);

            DrawHeader(spriteBatch);

            DrawMenuBody(spriteBatch);

            base.Draw(spriteBatch);
        }

        /// <summary>
        /// Draws the base menu, the overall popup panel on which the rest of the menu components are drawn.
        /// </summary>
        protected virtual void DrawBaseMenu(SpriteBatch spriteBatch)
        {
            Utils.DrawFilledRectangle(BackgroundColor, SizeAndShape, spriteBatch, Arroguella.GraphicsDevice);
            Utils.DrawRectangleBorder(SizeAndShape, 4, Color, spriteBatch, Arroguella.GraphicsDevice);
        }

        /// <summary>
        /// Draws the header section, possibly containing a title and subtitle
        /// </summary>
        protected virtual void DrawHeader(SpriteBatch spriteBatch)
        {
            // Header Box
            Utils.DrawFilledRectangle(Color, HeaderRect, spriteBatch, Arroguella.GraphicsDevice);

            // Title
            Utils.DrawString(spriteBatch, Font, Title, Color.White, TitleRect);

            // Subtitle
            Utils.DrawString(spriteBatch, Font, Subtitle, Color.White, SubtitleRect);  
        }


        protected virtual void DrawMenuBody(SpriteBatch spriteBatch)
        {
            // Options
            foreach (PopupMenuOption option in Options)
            {
                option.Draw(spriteBatch);
            }
        }

        /// <summary>
        /// Removes the selected choice from the menu
        /// </summary>
        public void RemoveSelectedChoice()
        {
            Options[SelectedOption].IsSelected = false;
            Choices.RemoveAt(SelectedOption);
            Options.RemoveAt(SelectedOption);

            // Select Previous
            if (--SelectedOption < 0)
            {
                SelectedOption = Choices.Count - 1;
            }

            if (SelectedOption >= 0)
            {
                Options[SelectedOption].IsSelected = true;
            }            
        }

        #endregion

        #region Menu Navigation

        /// <summary>
        /// Selects the next option in the menu
        /// </summary>
        public void SelectNext()
        {
            Options[SelectedOption].IsSelected = false;

            // Wrap around to the first
            if (++SelectedOption >= Choices.Count)
            {
                SelectedOption = 0;
            }

            Options[SelectedOption].IsSelected = true;
        }

        /// <summary>
        /// Selects the previous option in the menu
        /// </summary>
        public void SelectPrevious()
        {
            Options[SelectedOption].IsSelected = false;

            // Wrap around to the last
            if (--SelectedOption < 0)
            {
                SelectedOption = Choices.Count - 1;
            }

            Options[SelectedOption].IsSelected = true;
        }

        /// <summary>
        /// Returns the selected option in the menu
        /// </summary>
        /// <returns></returns>
        public object Select()
        {
            if (SelectedOption >= 0 && SelectedOption < Choices.Count)
            {
                return Choices[SelectedOption];
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// The index (in the List of options) of the currently selected (highlighted) option
        /// </summary>
        public int SelectedOption = -1;

        protected string Title;

        protected string Subtitle;

        protected List<object> Choices;

        new protected Rectangle SizeAndShape;

        protected Color Color;

        protected List<PopupMenuOption> Options = new List<PopupMenuOption>();

        protected Rectangle TitleRect;

        protected Rectangle SubtitleRect;

        protected Rectangle HeaderRect;

        protected Rectangle BodyRect;

        #endregion
    }
}
